package com.b2c.open.gateway.filter;

import com.b2c.open.gateway.utils.RSAUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 三方应用数据加密过滤器
 * @author liuyu07
 */
public class ResponseGatewayFilter implements GatewayFilter, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(ResponseGatewayFilter.class);

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        logger.info("三方应用数据加密过滤器, 开始");
        try {
            //获取response的 返回数据
            ServerHttpResponse originalResponse = exchange.getResponse();
            DataBufferFactory bufferFactory = originalResponse.bufferFactory();
            HttpStatus statusCode = originalResponse.getStatusCode();
            ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
                @Override
                public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                    Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                        //最重要的是这里，网上有很多对gateway响应进行修改的
                        //但是我这里会进行截断（并不是每次都截）
                        //刚开始也是按照buffer一个一个读，
                        // 然后看了下api 发现可以获取出所有流的集合
                        // 然后又继续查api 发现  DataBufferFactory 可以进行合并多个流的集合
                        //然后就把这个问题解决了。
                        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                        DataBuffer join = dataBufferFactory.join(dataBuffers);
                        byte[] content = new byte[join.readableByteCount()];
                        join.read(content);
                        //释放掉内存
                        DataBufferUtils.release(join);
                        String responseData = new String(content, StandardCharsets.UTF_8);

                        //responseData就是下游系统返回的内容,可以查看修改
                        logger.info("三方应用数据加密过滤器, 响应内容长度={}", responseData.length()<100?responseData:responseData.length());
                        String publicKey = stringRedisTemplate.opsForValue().get("open:gateway:publicKey");
                        String data = RSAUtils.encryptedDataOnJava(responseData, publicKey);
                        byte[] uppedContent = new String(data.getBytes(), Charset.forName("UTF-8")).getBytes();
                        return bufferFactory.wrap(uppedContent);
                    }));
                }
            };
            return chain.filter(exchange.mutate().response(decoratedResponse).build());
        } catch (Exception e) {
            logger.error("三方应用数据加密过滤器异常", e);
            return chain.filter(exchange);
        }
    }

    @Override
    public int getOrder() {
        //在NettyWriteResponseFilter之前
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 20;
    }
}
